//----------------------------------------------------------------------------
//  ,-.
// /_\___ ,   Ninja Framework
// '  ___\    (C) Riccardo Capra - http://riccar.do
//  //   \\
//----------------------------------------------------------------------------
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------

#ifndef NJ_REF_OBJECT_H
#	define NJ_REF_OBJECT_H

#	include "NjNinjaSyncLib.h"
#	include "NjRefObject_config.h"
#	include "NjAtomic.h"

	/// \brief Implements a lockless thread safe reference counted object
	///
	/// NjRefObject reference counter is 0 on newly created instances
	class NjRefObject
	{
	public:
		/// \brief The stroys this class instance
		virtual ~NjRefObject();

		/// \brief Increments the reference counter
		void IncrementReference();

		/// \brief Decrements the reference counter
		///
		/// If the reference counter goes to 0 the object is automatically destroyed
		void DecrementReference();

		/// Decrements the reference counter only if it is greater than 1
		/// 
		/// This means that calling this function it's guaranteed that the object will be never destroyed
		/// \return NJ_TRUE if the counter is decremented and NJ_FALSE if the counter was 1 and was not decremented.
		NjBool TryDecrementReference();

#	if NJ_REFERENCE_COUNTER_DEBUG
		/// \brief Returns current reference counter value
		NjUint GetReferenceCounterDebug() const;

		/// \brief Returns the total number of reference counted instances
		static NjUint GetTotalInstancesDebug();
#	endif // NJ_REFERENCE_COUNTER_DEBUG

	protected:
		/// \brief Creates a new reference counted object
		///
		/// Please note that the reference counter is 0 on newly created instances
		NjRefObject();
		NJ_TRIVIAL_COPY(NjRefObject);

		/// \brief Called before object destruction
		///
		/// If returns NJ_FALSE delete will be not called
		///
		/// The default implementation always returns NJ_TRUE
		virtual NjBool OnDispose();

	private:
		/// \brief Called before object destruction
		void Dispose();

		/// \brief The instance reference counter
		NjAtomic<NjUint> m_kCounter;

#	if NJ_REFERENCE_COUNTER_DEBUG
		/// \brief Total number of currently allocated instances
		static NjAtomic<NjUint> ms_kTotalInstancesDebug;
#	endif // NJ_REFERENCE_COUNTER_DEBUG
	};

#	include "NjAssert.h"
#	include "NjFundamentalLimits.h"
#	include "NjRefObject_inline.h"

#endif // NJ_REF_OBJECT_H
